﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic.Rules;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Analytics.DataObjects.Visuals;
using DiscoveryLogic.Common.Utilities;
using DiscoveryLogic.Workflows.Components.Entities;
using DiscoveryLogic.Workflows.Components.Entities.Distances.Comparers;
using MessageBox=System.Windows.Forms.MessageBox;
using UserControl=System.Windows.Controls.UserControl;

namespace DiscoveryLogic.Analytics.Modules.DedupRules
{
    /// <summary>
    /// Interaction logic for DedupRuleEditor.xaml
    /// </summary>
    public partial class DedupRuleEditor : UserControl
    {
        public delegate void OnDedupRuleUpdated(EntityDedupRule rule);
        public event OnDedupRuleUpdated DedupRuleUpdated;

        private EntityDedupRule _Rule;
        private Dictionary<string, Type> _ComparerNames;

        public DedupRuleEditor()
        {
            InitializeComponent();
            this._Rule=new EntityDedupRule(string.Empty,RuleType.Link,
                SetDataSourceType.XML, EntityType.Publications,
                EntityType.Publications,EntityIcons.DedupRuleIcon);
        }

        public DedupRuleEditor(EntityDedupRule rule):this()
        {
            this._Rule = rule;
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.cboEntityType.Items.Clear();
            foreach(EntityType entityType in Enum.GetValues(typeof(EntityType)))
            {
                this.cboEntityType.Items.Add(entityType.ToString());
            }
            Assembly assembly = typeof (IAttributeComparer).Assembly;
            Type[] types = assembly.GetTypes();
            this._ComparerNames=new Dictionary<string, Type>();
            foreach(Type type in types)
            {
                if(type.GetInterface(typeof(IAttributeComparer).FullName)!=null)
                {
                    this._ComparerNames.Add(type.Name, type);
                }
            }

            if(this._Rule !=null && !string.IsNullOrEmpty(this._Rule.RuleName))
            {
                this.txtRuleName.Text = this._Rule.RuleName;
                this.cboEntityType.Text = this._Rule.SrcEntityType.ToString();

                foreach (DataGridViewRow dr in this.dvFields.Rows)
                {
                    if (!dr.IsNewRow && dr.Cells[0].Value != null &&
                        dr.Cells[1].Value != null)
                    {
                        string fieldName = dr.Cells[1].Value.ToString();
                        if(this._Rule.DescAttrWeights.ContainsKey(fieldName))
                        {
                            dr.Cells[0].Value = true;
                            dr.Cells[2].Value = false;
                            dr.Cells[3].Value = this._Rule.DescAttrWeights[fieldName];
                        }
                        else if(this._Rule.AssocAttrWeights.ContainsKey(fieldName))
                        {
                            dr.Cells[0].Value = true;
                            dr.Cells[2].Value = true;
                            dr.Cells[3].Value = this._Rule.AssocAttrWeights[fieldName];
                        }
                        else
                        {
                            dr.Cells[0].Value = false;
                            dr.Cells[2].Value = false;
                            dr.Cells[3].Value = 0;
                            dr.Cells[4].Value = null;
                            dr.Cells[5].Value = 0;
                            continue;
                        }
                        foreach(string comparerName in this._ComparerNames.Keys)
                        {
                            if(this._Rule.Comparers !=null && this._Rule.Comparers.ContainsKey(fieldName) &&  
                                this._ComparerNames[comparerName]==this._Rule.Comparers[fieldName].GetType())
                            {
                                dr.Cells[4].Value = comparerName;
                                break;
                            }
                        }
                        dr.Cells[5].Value = this._Rule.Penalties.ContainsKey(fieldName)
                                                ? this._Rule.Penalties[fieldName]
                                                : 0;
                    }
                }

                this.sliderAssoc.Value = this._Rule.AssocThreshold;
                this.sliderCollapse.Value = this._Rule.CollapseThreshold;
            }
        }

        private void cboEntityType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if(!this.IsInitialized)
                return;

            if(this.cboEntityType.SelectedIndex>=0)
            {
                EntityType entityType =
                    (EntityType) Enum.Parse(typeof (EntityType), this.cboEntityType.SelectedItem.ToString());
                PropertyInfo[] props = EntityBase.GetProperties(entityType);
                this.dvFields.Rows.Clear();
                
                foreach(PropertyInfo prop in props)
                {
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewCheckBoxCell cellSelect=new DataGridViewCheckBoxCell();
                    cellSelect.Value = false;
                    dr.Cells.Add(cellSelect);
                    DataGridViewTextBoxCell cellField=new DataGridViewTextBoxCell();
                    cellField.Value = prop.Name;
                    dr.Cells.Add(cellField);
                    DataGridViewCheckBoxCell cellAssoc=new DataGridViewCheckBoxCell();
                    cellAssoc.Value = false;
                    dr.Cells.Add(cellAssoc);
                    DataGridViewTextBoxCell cellWeight=new DataGridViewTextBoxCell();
                    cellWeight.Value = 0.0;
                    dr.Cells.Add(cellWeight);
                    DataGridViewComboBoxCell cellComparer=new DataGridViewComboBoxCell();
                    foreach (string typeName in this._ComparerNames.Keys)
                        cellComparer.Items.Add(typeName);
                    dr.Cells.Add(cellComparer);
                    DataGridViewTextBoxCell cellPenalty=new DataGridViewTextBoxCell();
                    cellPenalty.Value = 0.0;
                    dr.Cells.Add(cellPenalty);

                    this.dvFields.Rows.Add(dr);
                }
            }
        }

        private void sliderAssoc_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!this.IsInitialized)
                return;
            this.lblAssocThrehold.Content = Math.Round(sliderAssoc.Value, 2);
        }

        private void sliderCollapse_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!this.IsInitialized)
                return;
            this.lblCollapseThrehold.Content = Math.Round(sliderCollapse.Value, 2);
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            EntityType entityType = (EntityType)Enum.Parse(typeof(EntityType), this.cboEntityType.SelectedItem.ToString());
            this._Rule=new EntityDedupRule(this.txtRuleName.Text,
                RuleType.Dedup, SetDataSourceType.XML,
                entityType,entityType,EntityIcons.DedupRuleIcon);
            this._Rule.DescAttrWeights=new Dictionary<string, double>();
            this._Rule.AssocAttrWeights=new Dictionary<string, double>();
            this._Rule.Comparers=new Dictionary<string, IAttributeComparer>();
            this._Rule.Penalties=new Dictionary<string, double>();
            this._Rule.AssocThreshold = this.sliderAssoc.Value;
            this._Rule.CollapseThreshold = this.sliderCollapse.Value;
            try
            {
                foreach (DataGridViewRow dr in this.dvFields.Rows)
                {
                    if (!dr.IsNewRow && dr.Cells[0].Value != null &&
                        dr.Cells[1].Value != null)
                    {
                        bool selected = bool.Parse(dr.Cells[0].Value.ToString());
                        if (!selected)
                            continue;
                        string fieldName = dr.Cells[1].Value.ToString();
                        bool isAssoc = bool.Parse(dr.Cells[2].Value.ToString());
                        double weight = double.Parse(dr.Cells[3].Value.ToString());
                        string comparerName = dr.Cells[4].Value.ToString();
                        Type comparerType = this._ComparerNames[comparerName];
                        IAttributeComparer comparer = (IAttributeComparer)Activator.CreateInstance(comparerType);
                        double penalty = double.Parse(dr.Cells[5].Value.ToString());
                        if (isAssoc)
                            this._Rule.AssocAttrWeights.Add(fieldName, weight);
                        else
                            this._Rule.DescAttrWeights.Add(fieldName, weight);
                        this._Rule.Comparers.Add(fieldName, comparer);
                        this._Rule.Penalties.Add(fieldName, penalty);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                MessageBox.Show(ex.Message);
                return;
            }
            

            RuleManager.Save(this._Rule);

            if (this.DedupRuleUpdated != null)
                this.DedupRuleUpdated(this._Rule);

            if(this.Parent is Window)
            {
                ((Window)this.Parent).Close();
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            if (this.Parent is Window)
            {
                ((Window)this.Parent).Close();
            }
        }
    }
}
